package org.dialMsg.Server.ServerImp;

import com.google.common.util.concurrent.RateLimiter;
import com.mjoys.report.common.pojo.mq.body.FactFollowMessage;
import com.mjoys.report.common.pojo.mq.body.FactManualCallMessage;
import com.mjoys.report.starter.api.FactMessageSendApi;
import org.apache.commons.lang3.RandomUtils;
import org.dialMsg.Mapper.ManualCallLogIdMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dialMsg.Pojo.MyFactSyncMqBody;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PreDestroy;

@Service
public class MaulResultsServerImp {
    @Autowired
    private ManualCallLogIdMapper manualCallLogIdMapper;
    @Autowired
    private FactMessageSendApi factMessageSendApi;
    private static final Logger logger = LoggerFactory.getLogger(MaulResultsServerImp.class);

    // 创建80个线程的线程池实现并发控制
    private final ExecutorService executor = Executors.newFixedThreadPool(80);

    // 用于控制速率的限流器（每秒80次操作）
    private static final RateLimiter rateLimiter = RateLimiter.create(3000.0);

    // 共享消息体对象
    private static final MyFactSyncMqBody myFactSyncMqBody = new MyFactSyncMqBody();

    // 当前最大ID状态（使用volatile保证可见性）
    private volatile int lastMaxId = 0;

    /**
     * 获取当前年月字符串 (格式: YYYYMM)
     */
    private String getCurrentYearMonth() {
        return new SimpleDateFormat("yyyyMM").format(new Date());
    }

    /**
     * 更新最后最大ID状态
     */
    private void updateLastMaxId(int maxId) {
        this.lastMaxId = maxId;
        myFactSyncMqBody.setManualCallLogId(maxId);
        logger.debug("更新最大ID: {}", maxId);
    }

    private FactManualCallMessage createSingleMessage(Integer id, String lineNumber, String targetPhone, Integer durationOfSeatConversing,
                                                      Integer callStatus, Integer batchDetailId, Integer contId, Integer followerId,
                                                      LocalDateTime callTime, LocalDateTime brokenTime, String oragenId) {
        FactManualCallMessage factManualCallMessage = new FactManualCallMessage();
        factManualCallMessage.setManualCallLogId(id);
        factManualCallMessage.setAiCallLogId(null);
        factManualCallMessage.setBatchSeatFirstCallToCustomerToday(true);
        factManualCallMessage.setBatchSeatFirstCallToCustomerConnectedToday(true);
        factManualCallMessage.setBatchDetailId(batchDetailId);
        factManualCallMessage.setBatchId(myFactSyncMqBody.getBatchId());
        factManualCallMessage.setSceneId(myFactSyncMqBody.getSceneId());
        factManualCallMessage.setLineNumber(lineNumber);
        factManualCallMessage.setSeatId(followerId);
        factManualCallMessage.setCallTime(callTime);
        factManualCallMessage.setEquipmentId(myFactSyncMqBody.getEquipmentId());
        factManualCallMessage.setTargetPhone(targetPhone);
        factManualCallMessage.setTargetCarrier(myFactSyncMqBody.getTargetCarrier());
        factManualCallMessage.setTargetProCity(myFactSyncMqBody.getTargetProCity());
        factManualCallMessage.setCallRecordPath(myFactSyncMqBody.getCallRecordPath());
        factManualCallMessage.setBrokenTime(brokenTime);
        factManualCallMessage.setCustomerName(myFactSyncMqBody.getCustomerName());
        factManualCallMessage.setDataOrgCode(oragenId);
        factManualCallMessage.setTenantId(myFactSyncMqBody.getTenantId());
        factManualCallMessage.setContId(String.valueOf(contId));
        factManualCallMessage.setDurationOfSeatRing(myFactSyncMqBody.getDurationOfSeatRing());
        factManualCallMessage.setCallStatus(callStatus);
        factManualCallMessage.setNumberType(myFactSyncMqBody.getNumberType());
        factManualCallMessage.setDurationOfSeatConversing(durationOfSeatConversing);
        factManualCallMessage.setCustSource(myFactSyncMqBody.getCustSource());
        factManualCallMessage.setManualCallType(myFactSyncMqBody.getManualCallType());
        factManualCallMessage.setBrokenUser(myFactSyncMqBody.getBrokenUser());
        return factManualCallMessage;
    }

    private FactFollowMessage createSingleMessage1(Integer id, String lineNumber, String targetPhone, Integer followResult,
                                                   Integer batchDetailId, Integer contId, Integer followerId,
                                                   LocalDateTime brokenTime, String oragenId, LocalDateTime callTime) {
        FactFollowMessage factFollowMessage = new FactFollowMessage();
        factFollowMessage.setManualCallLogId(id);
        factFollowMessage.setFollowerId(followerId);
        factFollowMessage.setManualCallTime(callTime);
        factFollowMessage.setFollowTime(brokenTime);
        factFollowMessage.setFollowResult(followResult);
        factFollowMessage.setFollowRemark(myFactSyncMqBody.getFollowRemark());
        factFollowMessage.setContId(String.valueOf(contId));
        factFollowMessage.setAiCallLogId(null);
        factFollowMessage.setBatchDetailId(batchDetailId);
        factFollowMessage.setBatchId(myFactSyncMqBody.getBatchId());
        factFollowMessage.setSceneId(myFactSyncMqBody.getSceneId());
        factFollowMessage.setLineNumber(lineNumber);
        factFollowMessage.setTargetPhone(targetPhone);
        factFollowMessage.setCustomerName(myFactSyncMqBody.getCustomerName());
        factFollowMessage.setDataOrgCode(oragenId);
        factFollowMessage.setTenantId(myFactSyncMqBody.getTenantId());
        factFollowMessage.setDistributeSeatId(myFactSyncMqBody.getDistributeSeatId());
        factFollowMessage.setDistributeTime(brokenTime);
        return factFollowMessage;
    }

    /**
     * 批量发送消息（每100条一批）
     *
     * @param messageCount 要发送的总消息数量
     */
    public void sendFactManualCallMessage(int messageCount) {
        if (messageCount <= 0) {
            logger.warn("消息数量无效: {}", messageCount);
            return;
        }

        // 定义批次大小（每批100条）
        final int batchSize = 3000;
        // 计算完整批次数和最后一批数量
        final int fullBatchCount = messageCount / batchSize;
        final int lastBatchSize = messageCount % batchSize;
        // 总批次数
        final int totalBatchCount = (lastBatchSize > 0) ? fullBatchCount + 1 : fullBatchCount;

        // 获取当前年月对应的最大ID
        final String yearMonth = getCurrentYearMonth();
        Integer initialMaxId = manualCallLogIdMapper.getMaxId(yearMonth);
        if (null == initialMaxId) {
            logger.warn("未找到当前年月的最大ID，将使用初始值 1");
            initialMaxId = 0;
        } else {
            updateLastMaxId(initialMaxId);
        }

        logger.info("开始批量发送{}条消息（分{}批），初始最大ID: {}",
                messageCount, totalBatchCount, initialMaxId);

        // 创建全局最大ID追踪器
        final AtomicInteger maxIdTracker = new AtomicInteger(initialMaxId);

        // 处理完整批次
        for (int batchIndex = 0; batchIndex < fullBatchCount; batchIndex++) {
            processBatch(batchIndex, batchSize, batchIndex * batchSize, initialMaxId, maxIdTracker);
        }

        // 处理最后不满一批的情况
        if (lastBatchSize > 0) {
            processBatch(fullBatchCount, lastBatchSize, fullBatchCount * batchSize, initialMaxId, maxIdTracker);
        }

        // 所有批次完成后更新最大ID
        final int finalMaxId = maxIdTracker.get();
        updateLastMaxId(finalMaxId);
        logger.info("所有批次发送完成！总计发送消息 {} 条，最终最大ID: {}", messageCount, finalMaxId);
    }

    /**
     * 处理单个消息批次
     *
     * @param batchIndex   批次序号（从0开始）
     * @param batchSize    当前批次大小
     * @param offset       当前批次的起始偏移量
     * @param baseId       批次ID计算的基准值
     * @param maxIdTracker 全局最大ID追踪器
     */
    private void processBatch(int batchIndex, int batchSize, int offset, int baseId, AtomicInteger maxIdTracker) {
        logger.info("开始处理第{}批次（{}条）", batchIndex + 1, batchSize);
        final AtomicLong phoneCounter = new AtomicLong(System.currentTimeMillis());

        // 创建批次计数器
        final CountDownLatch batchLatch = new CountDownLatch(batchSize);
        Integer BASE_DETAIL_ID = batchIndex + 1;
        // 计算当前批次起始ID
        final int batchStartId = baseId + offset + 1;
        // 提交批次内的所有任务
        for (int i = 0; i < batchSize; i++) {
            Integer results[] = {11, 20, 21};
            String oragenIds[] = {"17", "11468", "11014", "11494", "11153", "11016", "11026"};
            String l[] = {"057100204", "057100206", "057100205"};
            String targetPhone = String.valueOf(phoneCounter.incrementAndGet() % 10000000000L + 10000000000L).substring(1, 11);

//            String p[] = {"18037736334", "18037736333", "18037736332", "18037736335"};
            Integer[] zuoxi = {1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1779, 1780, 1781, 1782, 1783, 1784,
                    1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803};
            Integer c[] = {0, 1};
//            LocalDateTime callTime = LocalDateTime.now();
            LocalDateTime startTime = LocalDateTime.now().minusDays(1);
            LocalDateTime callTime = generateRandomDateTime(startTime);
            Integer durationOfSeatConversing;
            final int currentId = batchStartId + i;
            String lineNumber = l[RandomUtils.nextInt(0, l.length)];
//            String targetPhone = p[RandomUtils.nextInt(0, p.length)];
            Integer followResult = results[RandomUtils.nextInt(0, results.length)];
            Integer callStatus = c[RandomUtils.nextInt(0, c.length)];
            Integer followerId = zuoxi[RandomUtils.nextInt(0, zuoxi.length)];
            Integer batchDetailId = BASE_DETAIL_ID + currentId;
            Integer contId = BASE_DETAIL_ID + currentId;
            String oragenId = oragenIds[RandomUtils.nextInt(0, oragenIds.length)];
            if (callStatus == 0) {
                durationOfSeatConversing = 0;
                followResult = 21;
            } else {
                durationOfSeatConversing = 10;
            }
            Integer finalFollowResult = followResult;
            LocalDateTime brokenTime = callTime.plusSeconds(durationOfSeatConversing);

            executor.execute(() -> {
                try {
                    // 获取发送许可（控制80QPS）
                    rateLimiter.acquire();

                    // 发送两种消息
                    factMessageSendApi.send(createSingleMessage(currentId, lineNumber, targetPhone,
                            durationOfSeatConversing, callStatus, batchDetailId, contId, followerId, callTime, brokenTime, oragenId));
                    factMessageSendApi.send(createSingleMessage1(currentId, lineNumber, targetPhone,
                            finalFollowResult, batchDetailId, contId, followerId, brokenTime, oragenId, callTime));

                    // 更新最大ID（取当前批次最大值）
                    maxIdTracker.updateAndGet(prev -> Math.max(prev, currentId));

                    if (logger.isDebugEnabled()) {
                        logger.debug("消息发送完成: ID={}", currentId);
                    }
                } catch (Exception e) {
                    logger.error("消息发送失败, ID: {}", currentId, e);
                } finally {
                    batchLatch.countDown();  // 无论成功失败都计数
                }
            });
        }

        try {
            // 等待批次完成（超时5分钟）
            if (batchLatch.await(5, TimeUnit.MINUTES)) {
                logger.info("第{}批次处理完成（共{}条）", batchIndex + 1, batchSize);
            } else {
                logger.warn("第{}批次处理超时，剩余未完成: {}/{}",
                        batchIndex + 1, batchLatch.getCount(), batchSize);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.error("批次处理被中断: 批次{}", batchIndex + 1, e);
        }
    }

    public LocalDateTime generateRandomDateTime(LocalDateTime startDateTime) {
        LocalDateTime endDateTime = LocalDateTime.now();

        // 计算两个时间之间的秒数差
        long secondsDifference = Duration.between(startDateTime, endDateTime).getSeconds();

        // 生成随机秒数偏移量
        long randomSeconds = RandomUtils.nextLong(0, secondsDifference + 1);

        // 在开始时间基础上加上随机偏移量
        return startDateTime.plusSeconds(randomSeconds);
    }

    /**
     * 应用关闭时优雅关闭线程池
     */
    @PreDestroy
    public void shutdown() {
        logger.info("开始关闭消息发送服务...");
        executor.shutdown();
        try {
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                executor.shutdownNow();
                logger.warn("强制关闭线程池");
            }
            logger.info("消息发送服务已关闭");
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
            logger.error("关闭服务时被中断", e);
        }
    }
}